#include "stdafx.h"
#include "InputProcess.h"
#include "CommandParse.h"
#include "PacketProcess.h"


std::string g_strUser;

extern bool g_bWork;
extern short g_sLogin;

#define WAITING_OPT		0
#define CONFIRM_HELP	1
#define CONFIRM_CMD		2
#define CONFIRM_QUIT	3

static short s_sFlag = WAITING_OPT;
static TCHAR szCommand[MAX_GM_CMD_LEN + 1] = { 0 };

///help & function pair
bool AddGMOpt(const char* pInput);
bool RmvGMOpt(const char* pInput);
bool AddGroupOpt(const char* pInput);
bool RmvGroupOpt(const char* pInput);
bool AddExtraOpt(const char* pInput);
bool RmvExtraOpt(const char* pInput);
bool ChangePwdOpt(const char* pInput);


struct HelpOption
{
	const char* cmd;
	const char* notice;
	bool bVisible;
	bool (*fn)(const char*);
};

static HelpOption sHelpOptTable[] = 
{
	{ "add gm", "add gm user: ", true, AddGMOpt },
	{ "rmv gm", "rmv gm user: ", true, RmvGMOpt },
	{ "add group", "add gm group: ", true, AddGroupOpt },
	{ "rmv group", "rmv gm group: ", true, RmvGroupOpt },
	{ "add extra", "add gm extra: ", true, AddExtraOpt },
	{ "rmv extra", "rmv gm extra: ", true, RmvExtraOpt },
	{ "change pwd", "change pwd: ", false, ChangePwdOpt },
};

void SplitInput(const char* pContext,std::vector<std::string>& rVecParam,char cFlag = ' ',int nCount = -1)
{
	const char* pFlag = pContext;

	while ( pFlag != NULL )
	{
		pFlag = strchr( pContext, cFlag );

		if ( pFlag != NULL )
		{
			if ( pFlag != pContext )
			{
				rVecParam.push_back( std::string( pContext, pFlag ) );
				--nCount;
			}

			pContext = pFlag + 1;

			if ( nCount == 0 )
			{
				rVecParam.push_back( pContext );
				break;
			}
		}
		else
		{
			if ( *pContext != 0 )
			{
				rVecParam.push_back( pContext );
			}
		}
	}
}

void SendNetPacket(int nCmd,void* pData,int nSize)
{
	int nPacketLen = sizeof(MessageHeader) + nSize;
	xgc_byte* pPacket = new xgc_byte[nPacketLen];
	memcpy_s( pPacket + sizeof(MessageHeader), nSize, pData, nSize );

	MessageHeader* pHead = (MessageHeader*)pPacket;
	pHead->seq = 0;
	pHead->cmd = nCmd;
	pHead->length = nPacketLen;

	net::SendPacket( g_netHandle, pPacket, nPacketLen );
	delete[] pPacket;
}

void ShowHelpOption()
{
	printf( "choose option(press 'esc' to return):\n" );
	printf( "0 - %s\n", "command info" );

	for( int i = 0; i < _countof(sHelpOptTable); ++i )
	{
		printf( "%d - %s\n", i + 1, sHelpOptTable[i].cmd );
	}
}

bool AddGMOpt(const char* pInput)
{
	std::vector<std::string> vecParam;
	SplitInput( pInput, vecParam );

	if ( !vecParam.empty() && !vecParam[0].empty() && vecParam[0].size() <= MAX_GM_NAME_LEN )
	{
		char szGroup[ MAX_GM_GROUP_LEN + 1] = { 0 };

		if ( vecParam.size() == 2 )
		{
			if ( vecParam[1].size() <= MAX_GM_GROUP_LEN )
			{
				strcpy_s( szGroup, sizeof(szGroup), vecParam[1].c_str() );
			}
			else
			{
				return false;
			}
		}
		else if ( vecParam.size() > 2 )
		{
			return false;
		}

		SGM2C_ADDGM data;
		strcpy_s( data.szUser, sizeof(data.szUser), vecParam[0].c_str() );
		strcpy_s( data.szGroup, sizeof(data.szGroup), szGroup );
		SendNetPacket( GM2C_ADDGM, &data, sizeof(data) );
		
		return true;
	}

	return false;
}

bool RmvGMOpt(const char* pInput)
{
	std::vector<std::string> vecParam;
	SplitInput( pInput, vecParam );

	if ( vecParam.size() == 1 && !vecParam[0].empty() && vecParam[0].size() <= MAX_GM_NAME_LEN )
	{
		SGM2C_RMVGM data;
		strcpy_s( data.szUser, sizeof(data.szUser), vecParam[0].c_str() );
		SendNetPacket( GM2C_RMVGM, &data, sizeof(data) );

		return true;
	}

	return false;
}

bool AddGroupOpt(const char* pInput)
{
	std::vector<std::string> vecParam;
	SplitInput( pInput, vecParam );

	if ( vecParam.size() == 2
		&& !vecParam[0].empty()
		&& !vecParam[1].empty()
		&& vecParam[0].size() <= MAX_GM_NAME_LEN
		&& vecParam[1].size() <= MAX_GM_GROUP_LEN )
	{
		SGM2C_CHANGEGROUP data;
		data.bAdd = true;
		strcpy_s( data.szUser, sizeof(data.szUser), vecParam[0].c_str() );
		strcpy_s( data.szGroup, sizeof(data.szGroup), vecParam[1].c_str() );
		SendNetPacket( GM2C_CHGGROUP, &data, sizeof(data) );

		return true;
	}

	return false;
}

bool RmvGroupOpt(const char* pInput)
{
	std::vector<std::string> vecParam;
	SplitInput( pInput, vecParam );

	if ( !vecParam.empty() && !vecParam[0].empty() && vecParam[0].size() <= MAX_GM_NAME_LEN )
	{
		char szGroup[ MAX_GM_GROUP_LEN + 1] = { 0 };

		if ( vecParam.size() == 2 )
		{
			if ( vecParam[1].size() <= MAX_GM_GROUP_LEN )
			{
				strcpy_s( szGroup, sizeof(szGroup), vecParam[1].c_str() );
			}
			else
			{
				return false;
			}
		}
		else if ( vecParam.size() > 2 )
		{
			return false;
		}

		SGM2C_CHANGEGROUP data;
		data.bAdd = false;
		strcpy_s( data.szUser, sizeof(data.szUser), vecParam[0].c_str() );
		strcpy_s( data.szGroup, sizeof(data.szGroup), szGroup );
		SendNetPacket( GM2C_CHGGROUP, &data, sizeof(data) );

		return true;
	}

	return false;
}

bool AddExtraOpt(const char* pInput)
{
	std::vector<std::string> vecParam;
	SplitInput( pInput, vecParam, ' ', 1 );

	if ( vecParam.size() == 2
		&& !vecParam[0].empty()
		&& !vecParam[1].empty()
		&& vecParam[0].size() <= MAX_GM_NAME_LEN
		&& vecParam[1].size() <= MAX_GM_EXTRA_LEN )
	{
		SGM2C_CHANGEEXTRA data;
		data.bAdd = true;
		strcpy_s( data.szUser, sizeof(data.szUser), vecParam[0].c_str() );
		strcpy_s( data.szExtra, sizeof(data.szExtra), vecParam[1].c_str() );
		SendNetPacket( GM2C_CHGEXTRA, &data, sizeof(data) );

		return true;
	}

	return false;
}

bool RmvExtraOpt(const char* pInput)
{
	std::vector<std::string> vecParam;
	SplitInput( pInput, vecParam, ' ', 1 );

	if ( !vecParam.empty() && !vecParam[0].empty() && vecParam[0].size() <= MAX_GM_NAME_LEN )
	{
		char szExtra[ MAX_GM_EXTRA_LEN + 1] = { 0 };

		if ( vecParam.size() == 2 )
		{
			if ( vecParam[1].size() <= MAX_GM_EXTRA_LEN )
			{
				strcpy_s( szExtra, sizeof(szExtra), vecParam[1].c_str() );
			}
			else
			{
				return false;
			}
		}
		else if ( vecParam.size() > 2 )
		{
			return false;
		}

		SGM2C_CHANGEEXTRA data;
		data.bAdd = false;
		strcpy_s( data.szUser, sizeof(data.szUser), vecParam[0].c_str() );
		strcpy_s( data.szExtra, sizeof(data.szExtra), szExtra );
		SendNetPacket( GM2C_CHGEXTRA, &data, sizeof(data) );

		return true;
	}

	return false;
}

bool ChangePwdOpt(const char* pInput)
{
	std::vector<std::string> vecParam;
	SplitInput( pInput, vecParam );

	if ( vecParam.size() == 2
		&& !vecParam[0].empty()
		&& !vecParam[1].empty()
		&& vecParam[0].size() <= MAX_GM_PWD_LEN
		&& vecParam[1].size() <= MAX_GM_PWD_LEN )
	{
		SGM2C_CHANGEPWD data;
		strcpy_s( data.szOldPwd, sizeof(data.szOldPwd), vecParam[0].c_str() );
		strcpy_s( data.szNewPwd, sizeof(data.szNewPwd), vecParam[1].c_str() );
		SendNetPacket( GM2C_CHANGEPWD, &data, sizeof(data) );

		return true;
	}

	return false;
}

void Input_Login()
{
	DWORD dwRead = 0;
	TCHAR szUser[MAX_GM_NAME_LEN + 1] = { 0 };

	printf( "\ninput user(max %d): ", MAX_GM_NAME_LEN );
	g_strUser.clear();

	if( ReadConsole( GetStdHandle(STD_INPUT_HANDLE), szUser, sizeof(szUser), &dwRead, NULL ) != 0 )
	{
		if ( dwRead - 2 > 0 && dwRead - 2 < MAX_GM_NAME_LEN )
		{
			szUser[dwRead - 1] = 0;
			szUser[dwRead - 2] = 0;

			printf( "input pwd(max %d): ", MAX_GM_PWD_LEN );
			int nIndex = 0;
			TCHAR szPwd[MAX_GM_PWD_LEN + 1] = { 0 };

			while ( true )
			{
				if ( _kbhit() )
				{
					int ch = _gettch();
					if ( ch == 0x0d )
					{
						*(szPwd + nIndex) = 0;

						if ( nIndex > 0 )
						{
							g_sLogin = 0;

							SGM2C_LOGIN data;
							strcpy_s( data.szUser, sizeof(data.szUser), szUser );
							strcpy_s( data.szPwd, sizeof(data.szPwd), szPwd );
							SendNetPacket( GM2C_LOGIN, &data, sizeof(data) );

							printf( "\nuser login..." );
						}
						else
						{
							printf( "\npassword empty..." );
						}

						break;
					}
					else if ( ch == '\b' )
					{
						if ( nIndex > 0 )
						{
							printf( "\b \b" );
							--nIndex;
						}
					}
					else
					{
						if ( nIndex < MAX_GM_PWD_LEN )
						{
							*(szPwd + nIndex) = ch;
							++nIndex;

							printf( "*" );
						}
						else
						{
							printf( "\ninput error..." );
							break;
						}
					}
				}
			}
		}
		else
		{
			printf( "input error...\n" );
		}
	}
	else
	{
		printf( "system error...\n" );
	}
}

void Input_Yes()
{
	if( s_sFlag == CONFIRM_CMD )
	{
		printf( "y\n" );
		s_sFlag = WAITING_OPT;

		ParseCommand( szCommand );
	}
	else if ( s_sFlag == CONFIRM_QUIT )
	{
		printf( "y\n");
		s_sFlag = WAITING_OPT;

		printf( "now quit..." );
		g_bWork = false;
	}
}

void Input_No()
{
	if( s_sFlag == CONFIRM_CMD )
	{
		printf( "n\n" );
		s_sFlag = WAITING_OPT;
	}
	else if ( s_sFlag == CONFIRM_QUIT )
	{
		printf( "n\n" );
		s_sFlag = WAITING_OPT;
	}
}

void Input_Esc()
{
	if( s_sFlag == CONFIRM_CMD || s_sFlag == CONFIRM_QUIT || s_sFlag == CONFIRM_HELP )
	{
		printf( " esc...\n" );
		s_sFlag = WAITING_OPT;
	}
	else if ( s_sFlag == WAITING_OPT )
	{
		printf( "\nquit, sure?(Y/N)  " );
		s_sFlag = CONFIRM_QUIT;
	}
}

void Input_Help()
{
	if ( s_sFlag == WAITING_OPT )
	{
		printf( "\n" );

		ShowHelpOption();
		s_sFlag = CONFIRM_HELP;

		printf( "choose:" );
	}
}

void Input_Option(int n)
{
	if ( s_sFlag == CONFIRM_HELP )
	{
		printf( " %d\n", n );
		
		if ( n == 0 )
		{
			ShowCmdInfo();
		}
		else if ( n <= _countof(sHelpOptTable) )
		{
			printf( "%s", sHelpOptTable[n-1].notice );

			int nIndex = 0;
			TCHAR szInput[MAX_GM_CMD_LEN + 1] = { 0 };

			while ( true )
			{
				if ( _kbhit() )
				{
					int ch = _gettch();
					if ( ch == 0x0d )
					{
						printf( "\n" );
						*(szInput + nIndex) = 0;

						if ( !sHelpOptTable[n-1].fn( szInput ) )
						{
							printf( "input error...\n" );
						}

						break;
					}
					else if ( ch == 0x1b )
					{
						printf( "\n" );
						printf( "esc...\n" );
						break;
					}
					else if ( ch == '\b' )
					{
						if ( nIndex > 0 )
						{
							printf( "\b \b" );
							--nIndex;
						}
					}
					else
					{
						if ( nIndex < MAX_GM_CMD_LEN )
						{
							*(szInput + nIndex) = ch;
							++nIndex;

							if ( sHelpOptTable[n-1].bVisible )
							{
								printf( "%c", ch );
							}
							else
							{
								printf( "*" );
							}
						}
						else
						{
							printf( "\ninput error..." );
							break;
						}
					}
				}
			}
		}

		s_sFlag = WAITING_OPT;
	}
}

void Input_Enter()
{
	if ( s_sFlag == WAITING_OPT )
	{
		printf( "\n" );

		__time64_t _now;
		_time64(&_now);
		tm _tm;
		localtime_s( &_tm,&_now );
		printf( "%s %4d-%02d-%02d %02d:%02d:%02d>", g_strUser.c_str(), _tm.tm_year + 1900, _tm.tm_mon+1, _tm.tm_mday, _tm.tm_hour, _tm.tm_min, _tm.tm_sec );

		DWORD dwRead = 0;
		if( ReadConsole( GetStdHandle(STD_INPUT_HANDLE), szCommand, sizeof(szCommand), &dwRead, NULL ) )
		{
			if ( dwRead - 2 > 0 )
			{
				if ( dwRead - 2 < MAX_GM_CMD_LEN )
				{
					s_sFlag = CONFIRM_CMD;
					szCommand[dwRead - 1] = 0;
					szCommand[dwRead - 2] = 0;

					__time64_t _now;
					_time64(&_now);
					tm _tm;
					localtime_s( &_tm,&_now );
					printf( "%4d-%02d-%02d %02d:%02d:%02d : execute \"%s\", sure?(Y/N)  ", _tm.tm_year + 1900, _tm.tm_mon+1, _tm.tm_mday, _tm.tm_hour, _tm.tm_min, _tm.tm_sec, szCommand );
				}
				else
				{
					printf( "input error...\n" );
				}
			}
		}
		else
		{
			printf( "system error...\n" );
		}
	}
}

void ParseInput()
{
	if( _kbhit() )
	{
		int ch = _gettch();

		switch( ch )
		{
		case 'Y':
		case 'y':
			{
				Input_Yes();
			}
			break;
		case 'N':
		case 'n':
			{
				Input_No();
			}
			break;
		case 'H':
		case 'h':
			{
				Input_Help();
			}
			break;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
			{
				int n = ch - '0';
				Input_Option( n );
			}
			break;
		case 0x1b:
			{
				Input_Esc();
			}
			break;
		case 0x0d:
			{
				Input_Enter();
			}
			break;
		}
	}
}